Данные использовались в соревновании Ml Boot Camp 5.**
Вопросы в веб-форме.**
В соревновании предлагалось определить наличие/отсутствие сердечно-сосудистых заболеваний (ССЗ) по результатам осмотра пациента.
Описание данных.
Датасет сформирован из реальных клинических анализов, и в нём используются признаки, которые можно разбить на 3 группы:
Объективные признаки:
Результаты измерения:
Субъективные признаки (со слов пациентов):
Целевой признак (который интересно будет прогнозировать):
Значения показателей холестерина и глюкозы представлены одним из трех классов: норма, выше нормы, значительно выше нормы. Значения субъективных признаков — бинарны.
Все показатели даны на момент осмотра.
Мы будем работать только с обучающей выборкой и с помощью Pandas
проведем первичный анализ данных.
Из библиотек нам понадобятся только NumPy
и Pandas
.
In [1]:
import numpy as np
import pandas as pd
Считываем данные из CSV-файла в объект pandas DataFrame.
In [68]:
df = pd.read_csv('mlbootcamp5_train.csv', sep=';',
index_col='id')
Посмотрим на первые 5 записей.
In [4]:
df.head()
Out[4]:
Вопрос 1 (1 балл). Сколько мужчин и женщин представлено в этом наборе данных? Не было дано расшифровки признака "пол" (какому полу соответствует 1, а какому – 2 в признаке gender
) – это определите, посмотрев также на рост при разумном предположении, что в среднем мужчины выше (здесь и далее под средним понимается среднее арифметическое).
Варианты:
In [5]:
df[['height', 'gender']].groupby('gender').mean()
Out[5]:
In [7]:
df.groupby('gender').count()
Out[7]:
In [ ]:
24470 - M & 45530 Ж
Вопрос 2 (1 балл). Кто в среднем реже указывает, что употребляет алкоголь – мужчины или женщины?
Варианты:
In [22]:
df.groupby('gender')['alco'].sum()/df.groupby('gender')['alco'].count()
Out[22]:
Вопрос 3 (1 балл). Во сколько раз (округленно, round
) процент курящих среди мужчин больше, чем процент курящих среди женщин (по крайней мере, по этим анкетным данным)?
Варианты:
In [27]:
prop_smoke = df.groupby('gender')['smoke'].sum()/df.groupby('gender')['smoke'].count()
prop_smoke
Out[27]:
In [32]:
round(prop_smoke[2]/prop_smoke[1])
Out[32]:
Вопрос 4 (1 балл). Вы наверняка заметили, что значения возраста какие-то странные. Догадайтесь, в чём здесь измеряется возраст, и ответьте, на сколько месяцев (примерно) отличаются медианные значения возраста курящих и некурящих.
Варианты:
In [39]:
round((df.groupby('smoke')['age'].median()[0] - df.groupby('smoke')['age'].median()[1])/30)
#median
Out[39]:
Вопрос 5 (2 балла). В статье на Википедии про сердечно-сосудистый риск показана шкала SCORE для расчёта риска смерти от сердечно-сосудистого заболевания в ближайшие 10 лет. Вот она:
Давайте посмотрим на правый верхний прямоугольник, отображающий сегмент курящих мужчин в возрасте от 60 до 64 лет включительно. (Неочевидно, но тут для возраста и давления цифры означают верхнюю границу, и она не включается).
Видим 9-ку в левом нижнем углу этого прямоугольника и 47 – в правом верхнем. То есть если при этом систолическое (т.е. верхнее) артериальное давление – меньше 120 мм рт.ст., а уровень холестерина – 4 ммоль/л, то риск ССЗ оценивается примерно в 5 раз ниже, чем если бы давление лежало в интервале [160, 180), а холестерина было бы 8 ммоль/л.
Давайте посчитаем аналогичное значение, но на наших данных.
Уточнения:
age_years
– возраст в годах, округлив до целых (round
). Для данного примера отберите курящих мужчин от 60 до 64 лет включительноcholesterol
следующее: 4 ммоль/л $\rightarrow$ 1, 5-7 ммоль/л $\rightarrow$ 2, 8 ммоль/л $\rightarrow$ 3.Во сколько раз (округленно, round
) отличаются доли больных людей (согласно целевому признаку, cardio
) в этих двух подвыборках? Посчитайте на наших данных.
Варианты:
In [43]:
year_duration = 365.25
month_duration = 30.4167
In [66]:
df['age_years'] = round(df.age / year_duration).astype('int')
data = df[(df.smoke == 1) & (df.gender == 2) & (60 <= df.age_years) & (df.age_years < 65)]
part1 = data[(data.ap_hi < 120) & (data.cholesterol == 1)]
part2 = data[(160 <= data.ap_hi) & (data.ap_hi < 180) & (data.cholesterol == 3)]
part2.cardio.mean() / part1.cardio.mean()
Out[66]:
Вопрос 6 (2 балла). Постройте новый признак – BMI (Body Mass Index). Для этого надо вес в килограммах поделить на квадрат роста в метрах. Нормальными считаются значения BMI от 18.5 до 25. Выберите верные утверждения.
Утверждения:
In [69]:
df['BMI'] = df.weight / ((df.height / 100) ** 2)
print("median: " + str(df.BMI.median()))
print("women mean: " + str(df[df.gender == 1].BMI.mean()))
print("men mean: " + str(df[df.gender == 2].BMI.mean()))
print("healty mean: " + str(df[df.cardio == 0].BMI.mean()))
print("sick mean: " + str(df[df.cardio == 1].BMI.mean()))
print("teetotal healthy men mean: " + str(df[(df.gender == 2) & (df.alco == 0) & (df.cardio == 0)].BMI.mean()))
print("teetotal healthy women mean: " + str(df[(df.gender == 1) & (df.alco == 0) & (df.cardio == 0)].BMI.mean()))
Вопрос 7 (2 балла). Можно заметить, что данные не особо-то чистые, много в них всякой "грязи" и неточностей. Еще лучше мы это увидим, когда обсудим визуализацию данных.
Отфильтруйте следующие сегменты пациентов (считаем это ошибками в данных)
pd.Series.quantile
, если не знаете, что это такое – прочитайте)Это вовсе не вся чистка данных, которую можно было проделать, но пока остановимся на этом.
Сколько процентов данных (округленно, round
) мы выбросили?
Варианты:
In [70]:
height_low, height_high = df.height.quantile([.025, .975])
weight_low, weight_high = df.weight.quantile([.025, .975])
cond1 = (df.ap_lo > df.ap_hi)
cond2 = ((df.height < height_low) | (height_high < df.height))
cond3 = ((df.weight < weight_low) | (weight_high < df.weight))
unclean = (cond1 | cond2 | cond3)
print(unclean.sum())
print(df.shape[0])
print(unclean.sum() / df.shape[0])
df = df[~unclean]
print(df.shape[0])
In [49]:
5033/63259
Out[49]:
In [51]:
# print(df.count())
filter_pressure = df[df.ap_hi > df.ap_lo]
# print(filter_pressure.count())
filter_height = filter_pressure[(filter_pressure.height < filter_pressure.height.quantile(0.025)) | (filter_pressure.height > filter_pressure.height.quantile(0.975))]
# print(filter_height.count())
filter_weight = filter_height[(filter_height.weight < filter_height.weight.quantile(0.025)) | (filter_height.weight > filter_height.weight.quantile(0.975))]
print((df.count() - filter_weight.count())/df.count())
In [59]:
dfClear = df[(df['ap_lo']<=df['ap_hi']) & (df['height'] >= df['height'].quantile(0.025))
& (df['height'] <= df['height'].quantile(0.975))
& (df['weight'] >= df['weight'].quantile(0.025))
& (df['weight'] <= df['weight'].quantile(0.975))]
In [60]:
dfClear.shape
Out[60]:
In [61]:
len(dfClear)/len(df)
Out[61]: